from abc import ABC, abstractmethod, abstractproperty
import enum
import struct
from typing import Optional

from pydantic import BaseModel

class ChunkState(enum.Enum):
    Accepted = 0
    Rejected = 1
    Failed = 2
    Ended=3


class ChunkRecord(BaseModel):
    fid: int
    offset: int
    state: ChunkState = ChunkState.Accepted
    message: Optional[str]


class ChunkBase(ABC):
    @abstractmethod
    def get_bytes(self):
        pass

    @abstractproperty
    def offset(self):
        pass

    @abstractproperty
    def length(self):
        pass

    @abstractproperty
    def fid(self):
        pass

    @abstractproperty
    def ended(self):
        pass


class BufferChunk(ChunkBase):
    def __init__(self, chunk:bytes) -> None:
        view=memoryview(chunk)
        fmt='LLL'# 4B4B4B
        self._fid,self._offset,self._length=struct.unpack(fmt,view[:12])
        self.content=view[12:]
        if self.length!=len(self.content):
            raise Exception(f'Unpacking chunk buffer failure! Expect length: {self.length}, actual length {len(self.content)}')
    
    def get_bytes(self):
        return self.content
    
    @property
    def offset(self):
        return self._offset
    
    @property
    def length(self):
        return self._length
    
    @property
    def fid(self):
        return self._fid
    
    @property
    def ended(self):
        return self.length==0 or self.offset<0
    
    
    